/*
 * VHECRStandingsGrid.java
 * Created on 6 sept. 2009
 *
 * VirtualHockey Internet Platform
 * http://code.google.com/p/virtualhockey/
 *
 * Copyright (c) 2005-2009, Jens and Jan Janke (VirtualHockey Project)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 */

package com.hockeo.vhweb.client.ui.widget;

import java.util.ArrayList;
import java.util.Map;

import com.extjs.gxt.ui.client.Style;
import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.data.BasePagingLoadConfig;
import com.extjs.gxt.ui.client.data.BasePagingLoader;
import com.extjs.gxt.ui.client.data.PagingLoadConfig;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoader;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.GridEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnData;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;
import com.extjs.gxt.ui.client.widget.grid.RowNumberer;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.PagingToolBar;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.hockeo.vhweb.client.VHMain;
import com.hockeo.vhweb.client.mvc.VHController;
import com.hockeo.vhweb.client.res.VHResConstants;
import com.hockeo.vhweb.client.ui.menu.VHClubInfoContextMenu;
import com.hockeo.vhweb.client.ui.menu.VHGridContextMenu;
import com.hockeo.vhweb.client.utils.VHJsData;

/**
 * Special grid that displays the Earth Club Standings. It has paging support and supports
 * different sorting options.
 *
 * @version $Id$
 * @author jjanke
 */
public class VHECRStandingsGrid extends LayoutContainer
{
  private static final int                         PAGE_SIZE = 20;

  private final VHGridContextMenu                  d_ctxmenu;
  private final ListStore<VHJsData>                d_store;
  private Grid<VHJsData>                           d_grid;
  private PagingLoader<PagingLoadResult<VHJsData>> d_loader;
  private PagingToolBar                            d_pagingToolBar;
  private PagingLoadConfig                         d_pagingLoadConfig;
  private VHJsData                                 d_season  = null;
  private VHJsData                                 d_assoc   = null;

  /**
   * Builds a new ECR standings grid.
   *
   * @param controller the VH display controller
   * @param season the season for which to display the standings (leave <code>null</code>
   *          to retrieve data for the current season)
   * @param assoc the association for which to display the standings ( leave
   *          <code>null</code> to show data for all available associations)
   */
  public VHECRStandingsGrid( VHController controller, VHJsData season, VHJsData assoc )
  {
    d_season = season;
    d_assoc = assoc;
    d_store = createStore();

    setLayout( new FitLayout() );
    buildGrid();
    add( d_grid );

    d_ctxmenu = new VHClubInfoContextMenu( controller, d_grid, "club_" );
  }

  /**
   * Sets the season for which to display data and asks the table to reload itself.
   */
  public void setSeason( VHJsData season )
  {
    if ( d_season != null && d_season.getInt( "id" ) == season.getInt( "id" ) )
      return;

    d_season = season;

    // reset paging info
    //
    d_pagingLoadConfig = null;
    d_loader.load( getPagingLoadConfig( true ) );
  }

  public VHJsData getSeason()
  {
    return d_season;
  }

  /**
   * Sets the association for which to display data and asks the table to reload itself.
   */
  public void setAssociation( VHJsData assoc )
  {
    if ( d_assoc != null && d_assoc.getId().equals( assoc.getId() ) )
      return;

    d_assoc = assoc;
    d_loader.load( getPagingLoadConfig( true ) );
  }

  public VHJsData getAssocation()
  {
    return d_assoc;
  }

  /**
   * Returns the paging toolbar.
   */
  public final PagingToolBar getPagingToolBar()
  {
    return d_pagingToolBar;
  }

  protected ListStore<VHJsData> createStore()
  {
    RpcProxy<PagingLoadResult<VHJsData>> proxy = new RpcProxy<PagingLoadResult<VHJsData>>() {
      @SuppressWarnings( "synthetic-access" )
      @Override
      protected void load( Object objCfg, AsyncCallback<PagingLoadResult<VHJsData>> callback )
      {
        VHController.getBaseDataService().getECRStandings( (PagingLoadConfig) objCfg, VHController.getLocale(),
            ( d_season != null ? d_season.getInt( "id" ) : null ), ( d_assoc != null ? d_assoc.getId() : null ),
            callback );
      }
    };

    d_loader = new BasePagingLoader<PagingLoadResult<VHJsData>>( proxy );
    d_loader.setRemoteSort( true );

    d_pagingToolBar = new PagingToolBar( PAGE_SIZE );
    d_pagingToolBar.bind( d_loader );
    d_pagingToolBar.setBorders( true );

    return new ListStore<VHJsData>( d_loader );
  }

  private void buildGrid()
  {
    final NumberFormat numberFormat = NumberFormat.getFormat( "0.00" );
    GridCellRenderer<VHJsData> renderer = new GridCellRenderer<VHJsData>() {
      public String render( VHJsData data, String strProperty, ColumnData config, int rowIndex, int colIndex,
          ListStore<VHJsData> store, Grid<VHJsData> grid )
      {
        if ( strProperty.equals( "rank" ) )
          return "<span style='font-weight: bold;'>" + data.getInt( strProperty ) + "</span>";
        else if ( strProperty.equals( "rankTendency" ) )
          return "<img src='images/picto/rank_" + data.getString( "rankTendency" ).toLowerCase() + ".gif'/>";
        else if ( strProperty.equals( "club_country" ) )
          return "<img src='images/flags/16x16/" + data.getString( "club_country" ) + ".png'/>";

        return String.valueOf( data.get( strProperty ) );
      }
    };

    // Column definitions
    //
    VHResConstants constants = VHMain.getConstants();
    ArrayList<ColumnConfig> listCols = new ArrayList<ColumnConfig>();
    ColumnConfig col;

    RowNumberer rowNumberer = new RowNumberer();
    listCols.add( rowNumberer );

    col = new ColumnConfig();
    col.setId( "rank" );
    col.setHeader( constants.rankAbbrev() );
    col.setToolTip( constants.rank() );
    col.setWidth( 28 );
    col.setRenderer( renderer );
    col.setAlignment( HorizontalAlignment.RIGHT );
    col.setResizable( false );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "rankTendency" );
    col.setHeader( constants.rankTendencyAbbrev() );
    col.setToolTip( constants.rankTendency() );
    col.setWidth( 26 );
    col.setRenderer( renderer );
    col.setAlignment( HorizontalAlignment.CENTER );
    col.setResizable( false );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "prevRank" );
    col.setHeader( constants.prevRankAbbrev() );
    col.setToolTip( constants.prevRank() );
    col.setWidth( 28 );
    col.setAlignment( HorizontalAlignment.RIGHT );
    col.setResizable( false );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "rankDiff" );
    col.setHeader( constants.rankDiffAbbrev() );
    col.setToolTip( constants.rankDiff() );
    col.setWidth( 35 );
    col.setNumberFormat( NumberFormat.getFormat( "+#;-#" ) );
    col.setAlignment( HorizontalAlignment.RIGHT );
    col.setResizable( false );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "club_country" );
    col.setHeader( constants.countryAbbrev() );
    col.setToolTip( constants.country() );
    col.setWidth( 26 );
    col.setRenderer( renderer );
    col.setAlignment( HorizontalAlignment.CENTER );
    col.setResizable( false );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "club_name" );
    col.setHeader( constants.clubName() );
    col.setWidth( 200 );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsTotal" );
    col.setHeader( constants.pointsTotalAbbrev() );
    col.setToolTip( constants.pointsTotal() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS1" );
    col.setHeader( constants.pointsS1Abbrev() );
    col.setToolTip( constants.pointsS1() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS2" );
    col.setHeader( constants.pointsS2Abbrev() );
    col.setToolTip( constants.pointsS2() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS3" );
    col.setHeader( constants.pointsS3Abbrev() );
    col.setToolTip( constants.pointsS3() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS4" );
    col.setHeader( constants.pointsS4Abbrev() );
    col.setToolTip( constants.pointsS4() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS5" );
    col.setHeader( constants.pointsS5Abbrev() );
    col.setToolTip( constants.pointsS5() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS1League" );
    col.setHeader( constants.pointsS1LeagueAbbrev() );
    col.setToolTip( constants.pointsS1League() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS1Cup" );
    col.setHeader( constants.pointsS1CupAbbrev() );
    col.setToolTip( constants.pointsS1Cup() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS1EU1" );
    col.setHeader( constants.pointsS1EU1Abbrev() );
    col.setToolTip( constants.pointsS1EU1() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsS1EU2" );
    col.setHeader( constants.pointsS1EU2Abbrev() );
    col.setToolTip( constants.pointsS1EU2() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "pointsExpiringNextSeason" );
    col.setHeader( constants.pointsExpiringAbbrev() );
    col.setToolTip( constants.pointsExpiring() );
    col.setWidth( 40 );
    col.setNumberFormat( numberFormat );
    col.setAlignment( HorizontalAlignment.RIGHT );
    listCols.add( col );

    final ColumnModel cm = new ColumnModel( listCols );

    // Grid
    //
    d_grid = new Grid<VHJsData>( d_store, cm );
    d_grid.addPlugin( rowNumberer );
    d_grid.setStripeRows( true );
    d_grid.setBorders( true );
    d_grid.setAutoWidth( true );

    d_grid.setStateId( "ecrStandingsGrid" );
    d_grid.setStateful( true );
    d_grid.addListener( Events.Attach, new Listener<GridEvent<VHJsData>>() {
      @SuppressWarnings( "synthetic-access" )
      public void handleEvent( GridEvent<VHJsData> be )
      {
        d_loader.load( getPagingLoadConfig( false ) );
      }
    } );
  }

  /**
   * Returns the paging load configuration (the one that indicates which page to load and
   * by which field to sort etc.).
   *
   * @param fResetOffset whether to reset the offset so that the next returned results
   *          will be from the first page
   */
  private PagingLoadConfig getPagingLoadConfig( boolean fResetOffset )
  {
    if ( d_pagingLoadConfig == null )
    {
      d_pagingLoadConfig = new BasePagingLoadConfig();
      d_pagingLoadConfig.setOffset( 0 );
      d_pagingLoadConfig.setLimit( PAGE_SIZE );
    }
    else if ( fResetOffset )
      d_pagingLoadConfig.setOffset( 0 );

    Map<String, Object> state = d_grid.getState();
    if ( !fResetOffset && state.containsKey( "offset" ) )
    {
      int offset = (Integer) state.get( "offset" );
      int limit = (Integer) state.get( "limit" );
      d_pagingLoadConfig.setOffset( offset );
      d_pagingLoadConfig.setLimit( limit );
    }
    if ( state.containsKey( "sortField" ) )
    {
      d_pagingLoadConfig.setSortField( (String) state.get( "sortField" ) );
      d_pagingLoadConfig.setSortDir( Style.SortDir.valueOf( (String) state.get( "sortDir" ) ) );
    }

    return d_pagingLoadConfig;
  }
}
